package exportSystem.statistics;

import gameEngine.agents.Agent;
import gameEngine.agents.teamMateModel.AgentMock;
import gameEngine.agents.teamMateModel.TeamMateModel;

import java.util.ArrayList;
import java.util.HashMap;

import org.apache.log4j.Logger;

/**
 * class that holds statistics function for logs and formaters use
 * @author alon
 *
 */
public class Statistics {

	private static ArrayList<Agent> agents;
	private static Statistics stats;
	private static int[][] passTable;
	private static HashMap<Integer,Integer> stopAverage=new HashMap<Integer,Integer>();
	private static Logger log = Logger.getLogger(exportSystem.statistics.Statistics.class);
	
	private Statistics(){
		
	}
	
	public static void initStatistics(ArrayList<Agent> agents){
		Statistics.agents=agents;
		passTable=new int[agents.size()][agents.size()];
	}
	
	/**
	 * create the singlton the singelton
	 * @param agents list of real agents
	 */
	public static synchronized void create(){
		stats=new Statistics();
	}
	
	public static Statistics getInstace(){
		if(stats==null){
			log.debug("Statistics not created");
		}
		return stats;
	}
	
	/**
	 * Calculates the Accuracy of the competence
	 * @param mocks The Agents mocks from the {@link TeamMateModel} 
	 * @param myID agent ID so we wont calculate it as it is not predicted 
	 * @return Accuracy in percentage
	 */
	public static double calculateAqurecy(ArrayList<AgentMock> mocks,int myID){
		int agentNum=agents.size();
		double realComp;
		double mockComp;
		double sum=0.0;
		for(int i=0;i<agentNum;i++){
			realComp=agents.get(i).getCompetence();
			mockComp=mocks.get(i).getAgentCompitance();
			if(agents.get(i).getID()!=myID){
				if(realComp>0.5){
					sum+=(1-((Math.abs(realComp-mockComp))/realComp))*(100/(agentNum-1));
				}else{
					sum+=(1-((Math.abs(realComp-mockComp))/(1-realComp)))*(100/(agentNum-1));
				}
			}
		}
		return sum;
	}
	
	/**
	 * calculates the Accuracy of the epsilon Greedy
	 * @param mocks The Agents mocks from the {@link TeamMateModel} 
	 * @param myID agent ID so we wont calculate it as it is not predicted 
	 * @return Accuracy in percentage
	 */
	public static double calculateEpsilonAqurecy(ArrayList<AgentMock> mocks,int myID){
		int agentNum=agents.size();
		double realeps;
		double mockeps;
		double sum=0.0;
		for(int i=0;i<agentNum;i++){
			realeps=agents.get(i).getEpsilonGreedy();
			mockeps=mocks.get(i).getAgentEGreedy();
			if(agents.get(i).getID()!=myID){
				if(realeps>0.5){
					sum+=(1-((Math.abs(realeps-mockeps))/realeps))*(100/(agentNum-1));
				}else{
					sum+=(1-((Math.abs(realeps-mockeps))/(1-realeps)))*(100/(agentNum-1));
				}
			}
		}
		return sum;
	}
	/**
	 * adds a passing to the pass table
	 * @param sender the sending agent id
	 * @param reciver receiving agent id
	 */
	public static void addPass(int sender,int reciver){
		passTable[sender-1][reciver-1]++;
	}
	
	/**
	 * return a table eith counts of passing from agent to agent
	 * for example 
	 * 1 2
	 * 2 0
	 * means that agent 1 passed to him self 1 time and to agent 2 2 times
	 * agent 2 passed to agent 1 2 times self 0 times 
	 * @return int[][]
	 */
	public static int[][] getPassTable(){
		return passTable;
	}
	
	/**
	 * adding a the turn number where game stopped to agents sum
	 * @param id id
	 * @param turn turn
	 */
	public static void addAgentStopTurn(int id,int turn){
		if(stopAverage.get(id)==null){
			stopAverage.put(id, turn); 
		}else{
			int sum=stopAverage.get(id);
			sum+=turn;
			stopAverage.put(id, sum);
		}
	}
	
	public static double getAgentStopAvarage(int id,int turns){
		return ((double)stopAverage.get(id))/turns;
	}
	
}
